package com.hj.service.impl;

import cn.hutool.core.map.MapUtil;
import com.hj.domain.HjToken;
import com.hj.domain.LoginUser;
import com.hj.domain.constant.HjConstant;
import com.hj.service.HjTokenService;
import com.hj.util.RedisUtil;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Description token 处理
 * @author hj
 */
@Service
@Slf4j
public class HjTokenServiceImpl implements HjTokenService {

    @Value("${jwt.expiration}")
    private long expiration;
    @Value("${jwt.secret}")
    private String secret;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public HjToken save(LoginUser loginUser) {
        loginUser.setToken(UUID.randomUUID().toString());
        String jwtToken = createJwtToken(loginUser);
        cacheLoginUser(loginUser);
        HjToken hjToken = new HjToken();
        hjToken.setToken(jwtToken);
        hjToken.setLoginTime(loginUser.getLoginTime());
        return hjToken;
    }

    @Override
    public void refresh(LoginUser loginUser) {
        cacheLoginUser(loginUser);
    }

    @Override
    public LoginUser get(String jwtToken) {
        String uuid = getUuidFromJwt(jwtToken);
        if (null != uuid) {
            return redisUtil.get(getTokenKey(uuid), LoginUser.class);
        }
        return null;
    }

    @Override
    public void delete(String jwtToken) {
        String uuid = getUuidFromJwt(jwtToken);
        if (null != uuid) {
            String tokenKey = getTokenKey(uuid);
            redisUtil.del(tokenKey);
        }
    }


    private void cacheLoginUser(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + expiration * 1000);
        redisUtil.set(getTokenKey(loginUser.getToken()), loginUser, expiration, TimeUnit.SECONDS);
    }

    private String createJwtToken(LoginUser loginUser) {
        Map<String, Object> claims = new HashMap<>(1);
        claims.put(HjConstant.LOGIN_USER_KEY, loginUser.getToken());
        String jwtToken = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
        log.info("jwtToken:" + jwtToken);
        return jwtToken;
    }

    private String getUuidFromJwt(String jwtToken) {
        try {
            Map<String, Object> claims = Jwts.parser().setSigningKey(secret)
                    .parseClaimsJws(jwtToken).getBody();
            return MapUtil.getStr(claims, HjConstant.LOGIN_USER_KEY);
        } catch (JwtException e) {
            log.error("{}已过期", jwtToken);
        } catch (Exception e) {
            log.error("{}", e.getMessage());
        }
        return null;
    }

    private String getTokenKey(String uuid) {
        return "tokens:" + uuid;
    }

}
